'''
Created on 19/08/2012

@author: Nrai
'''
from src.ex import paletteexceptions
import sys


def validate_palette(palette, ext):
    
    '''
        Receives either a file, list or string and dispatches it
        to the proper validation function.
    '''
    #Placeholder for palette config
    palette_properties = {"act" : {"length" : 768, "channels" : 3} }
    
    length = palette_properties[ext]["length"]
    channels = palette_properties[ext]["channels"]
    ptype = get_ptype(palette)  # Find the object type (file, str, list)
    validator = None            #dynamic validator based on ptype
    try:
        validator = getattr(sys.modules[__name__], 
                            "validate_{p}".format(p = ptype))
    except AttributeError:
        raise paletteexceptions.PaletteHandlingError(ptype)
    try:
        return validator(
                         palette, 
                         ext = ext, 
                         length = length, 
                         channels = channels
                         )
    except AttributeError:
        raise paletteexceptions.PaletteError(palette) 
    

def validate_file(pfile, ext, length, channels):
    
    '''
        Validate that the palette object is of type file
        Validates the extension of the file.
        Validates the length of the file.
    '''
    try:
        ftype = type(pfile)
        assert ftype is file
    except AssertionError:
        raise paletteexceptions.PaletteFileError(
                                                 "%s must be a file object" 
                                                 % pfile.name
                                                 )
    try:
        pfile_ext = pfile.name.split(".")[1]
        assert pfile_ext == ext
    except AssertionError:
        raise paletteexceptions.PaletteFileError(pfile.name)
    try:
        sof, eof = 0, 2
        pfile.seek(sof, eof)
        plength = pfile.tell()
        assert plength == length
    except AssertionError:
        pfile.close()
        raise paletteexceptions.PaletteLengthError(length, plength)
    pfile.seek(sof)
    return True


def validate_str(ustring, ext, length, channels):
    
    ''' 
        Validates the length of the string,
        That every character is decoded as an int,
        That every int ranges from 0 to 255
        
        Length can be specified for particular file type
        default is 768 for .act files
    '''
    
    try:
        "Asserts the length of the string"
        plength = len(ustring)
        assert plength == length
    except AssertionError:
        raise paletteexceptions.PaletteLengthError(length, plength)
    for char in ustring:
        try:
            "Tries to convert the char to it's int unicode"
            char = ord(char)
            try:
                "Asserts that the result was an int"
                assert type(char) is int
            except AssertionError:
                raise paletteexceptions.PaletteValueError(char)
            try:
                "Asserts that the int is in range 0-255"
                assert char >=0 and char <= 255
            except AssertionError:
                raise paletteexceptions.PaletteRangeError(char)
        except TypeError:
            raise paletteexceptions.PaletteFormatError(char)
    return True
  
            
def validate_list(clist, ext, length, channels):
    
    '''
        Receives a nested list with colors.
        Validates the length of the list
        Validates the length of each color(channels)
        Validates that each channel is an int
        Validates that each channel ranges from 0 to 255.
    '''
    
    length = length / channels
    try:
        assert type(clist) is list
    except AssertionError:
        raise paletteexceptions.PaletteError("Palette must be a list")
    try:
        clength = len(clist)
        assert clength == length
    except AssertionError:
        raise paletteexceptions.PaletteLengthError(length, clength)
        
    for color in clist:
        try:
            assert type(color) is list
        except AssertionError:
            raise paletteexceptions.PaletteError("Color must be a list")
        try:
            cchannels = len(color)
            assert cchannels == channels
        except AssertionError:
            raise paletteexceptions.PaletteLengthError(channels, cchannels)
        for channel in color:
            try:
                assert type(channel) is int
            except AssertionError:
                raise paletteexceptions.PaletteValueError(channel)
            try:
                assert channel >= 0 and channel <= 255
            except AssertionError:
                raise paletteexceptions.PaletteRangeError(channel)
    return True


def get_ptype(palette):
    try:
        ptype = str(type(palette)).split("'")[1]
        assert ptype in ["file", "list", "str"]
    except AssertionError:
        raise paletteexceptions.PaletteHandlingError(ptype)
    return ptype